package com.marathon.ershor.textrecognizer;

import android.Manifest;
import android.app.Activity;
import android.content.res.Configuration;
import android.graphics.Bitmap;
import android.hardware.Camera;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.HandlerThread;
import android.util.Log;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.Window;
import android.view.WindowManager;
import android.widget.TextView;

import java.io.File;
import java.util.List;

import kr.co.namee.permissiongen.PermissionFail;
import kr.co.namee.permissiongen.PermissionGen;


public class MainActivity extends Activity implements SurfaceHolder.Callback {

    private static final String TAG = "MainActivity";

    SurfaceHolder mHolder;
    Camera mCamera;
    Handler mHandlerIO;
    Handler mHandlerUI;
    RecResultView mRecResultView;
    TextView mInfo;

    boolean mSurfaceOK = false;
    boolean mIOThreadOK = false;

    public void takePictureAction() {
        try {
            mCamera.startPreview();
            setInfo("takePicture");
            Log.d(TAG, "takePicture, thread id:" + Thread.currentThread().getId());
            mCamera.takePicture(null, null, jpegCallback);
        } catch (Exception e) {
            e.printStackTrace();
            setInfo(e.toString());
            mHandlerIO.postDelayed(mIORunnableTakePicture, 200);
        }
    }

    public void setInfo(final String strInfo) {
//        mHandlerUI.post(new Runnable() {
//            @Override
//            public void run() {
//                mInfo.setText(strInfo);
//            }
//        });
    }

    Camera.PictureCallback jpegCallback = new Camera.PictureCallback() {
        @Override
        public void onPictureTaken(byte[] data, Camera camera) {
            mCamera.startPreview();
            Log.d(TAG, "onPictureTaken, thread id:" + Thread.currentThread().getId());
            if (data == null) {
                setInfo("onPictureTaken fail");
                return;
            }

            try {
                Uri jpgUri = ImageDealer.JpegDataToUri(data);
                int curOrientation =
                        MainActivity.this.getResources().getConfiguration().orientation;
                Bitmap bmp = null;
                if (curOrientation == Configuration.ORIENTATION_PORTRAIT) {
                    bmp = ImageDealer.getRotatedImagePath(jpgUri.getPath());
                } else {
                    bmp = ImageDealer.decodeSampledBitmapFromFile(jpgUri.getPath(), 2000, 2000);
                }

                int width = bmp.getWidth();
                int height = bmp.getHeight();
                File rotatedJpeg = new File(jpgUri.getPath());

                setInfo("recognize");
                String strJsonResult = OKHttpUploader.recognizeImage(rotatedJpeg, width/2, height/2, 0.7f);
                setInfo(strJsonResult);
                mRecResultView.setJson(strJsonResult, width, height);

                mCamera.autoFocus(null);

            } catch (Exception e) {
                e.printStackTrace();
                setInfo(e.toString());
            }
            mHandlerIO.postDelayed(mIORunnableTakePicture, 500);
        }
    };

    Runnable mIORunnableTakePicture = new Runnable() {
        @Override
        public void run() {
            takePictureAction();
        }
    };

    public void createIOThread() {
        HandlerThread handlerThread = new HandlerThread("takePicture");
        handlerThread.start();
        mHandlerIO = new Handler(handlerThread.getLooper());
        mIOThreadOK = true;
        if (mSurfaceOK)
            initCameraInIO();
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().requestFeature(Window.FEATURE_NO_TITLE);
        super.onCreate(savedInstanceState);

        mHandlerUI = new Handler();
        createIOThread();

        setContentView(R.layout.activity_main);
        SurfaceView surface = findViewById(R.id.camera_frame);
        mRecResultView = findViewById(R.id.rec_result_view);
        mInfo = findViewById(R.id.info_text);

        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);

        mHolder = surface.getHolder();
        mHolder.addCallback(MainActivity.this);
        mHolder.setType(SurfaceHolder.SURFACE_TYPE_PUSH_BUFFERS);

        requestPermission();
    }

    @Override
    public void onRequestPermissionsResult(int requestCode, String[] permissions,
                                           int[] grantResults) {
        PermissionGen.onRequestPermissionsResult(this, requestCode, permissions, grantResults);
    }

    public void requestPermission() {
        PermissionGen.with(MainActivity.this)
                .addRequestCode(100)
                .permissions(
                        Manifest.permission.READ_PHONE_STATE,
                        Manifest.permission.READ_EXTERNAL_STORAGE,
                        Manifest.permission.WRITE_EXTERNAL_STORAGE,
                        Manifest.permission.CAMERA)
                .request();
    }

    @PermissionFail(requestCode = 100)
    public void PermissionFail() {
        requestPermission();
    }

    @Override
    public void surfaceCreated(SurfaceHolder holder) {
        //IO thread to new mCamera, so that takePicture can take place at IO thread
    }

    private void initCamera() {

        Log.d("initCameraFunc", "1");
        try {
            if (mCamera == null)
                mCamera = Camera.open();

            mCamera.lock();
            int curOrientation =
                    MainActivity.this.getResources().getConfiguration().orientation;
            if (curOrientation == Configuration.ORIENTATION_PORTRAIT) {
                mCamera.setDisplayOrientation(90);
            }

            Camera.Parameters parameters = mCamera.getParameters();
            Camera.Size cs = getSameSmallestPreviewPictureSize();
            if (cs == null) {
                setInfo("same preview and picture size do not exists");
                return;
            }

            Log.d("initCameraFunc", "2");

            parameters.setPreviewSize(cs.width, cs.height);
            parameters.setPictureSize(cs.width, cs.height);
            mCamera.setParameters(parameters);
            mCamera.startPreview();
            mCamera.setPreviewDisplay(mHolder);
            mHandlerIO.post(mIORunnableTakePicture);

            Log.d("initCameraFunc", "3");
        } catch (Exception e) {
            e.printStackTrace();
            initCameraInIO();
        }
    }

    private void initCameraInIO() {
        mHandlerIO.postDelayed(new Runnable() {
            @Override
            public void run() {
                initCamera();
            }
        }, 500);
    }


    @Override
    public void surfaceChanged(SurfaceHolder holder, int format, int width, int height) {
        mSurfaceOK = true;
        if (mIOThreadOK)
            initCameraInIO();
    }

    @Override
    public void surfaceDestroyed(SurfaceHolder holder) {
        if (mCamera != null) {
            mCamera.stopPreview();
            mCamera.release();
            mCamera = null;
        }
    }

    private Camera.Size getSameSmallestPreviewPictureSize() {
        List<Camera.Size> sizesPicture = mCamera.getParameters().getSupportedPictureSizes();
        List<Camera.Size> sizesPreview = mCamera.getParameters().getSupportedPreviewSizes();
        for (Camera.Size size : sizesPicture) {
            if (sizesPreview.contains(size))
                return size;
        }
        return null;
    }

}
